1 /*
2  * Collie - An asynchronous event-driven network framework using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd 
5  *
6  * Developer: putao's Dlang team
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 module collie.codec.http.parser.parsertype;
12 
13 enum HTTPParserType
14 {
15     HTTP_REQUEST,
16     HTTP_RESPONSE,
17     HTTP_BOTH
18 }
19 
20 
21 enum HTTPParserErrno
22 {
23     /* No error */
24     HPE_OK = 0, //"success")                                                  \
25 
26     /* Callback-related errors */
27     HPE_CB_MessageBegin = 1, //"the on_message_begin callback failed")       \
28     HPE_CB_Url = 2, // "the on_url callback failed")                           \
29     HPE_CB_HeaderField = 3, //"the on_header_field callback failed")         \
30     HPE_CB_HeaderValue = 4, //"the on_header_value callback failed")         \
31     HPE_CB_HeadersComplete = 5, //"the on_headers_complete callback failed") \
32     HPE_CB_Body = 6, //"the on_body callback failed")                         \
33     HPE_CB_MessageComplete = 7, // "the on_message_complete callback failed") \
34     HPE_CB_Status = 8, // "the on_status callback failed")                     \
35     HPE_CB_ChunkHeader = 9, //"the on_chunk_header callback failed")         \
36     HPE_CB_ChunkComplete = 10, //"the on_chunk_complete callback failed")     \
37 
38     /* Parsing-related errors */
39     HPE_INVALID_EOF_STATE = 11, // "stream ended at an unexpected time")        \
40     HPE_HEADER_OVERFLOW = 12, // "too many header bytes seen; overflow detected")                \
41     HPE_CLOSED_CONNECTION = 13, // "data received after completed connection: close message")      \
42     HPE_INVALID_VERSION = 14, // "invalid HTTP version")                        \
43     HPE_INVALID_STATUS = 15, //"invalid HTTP status code")                     \
44     HPE_INVALID_METHOD = 16, //"invalid HTTP method")                          \
45     HPE_INVALID_URL = 17, //"invalid URL")                                     \
46     HPE_INVALID_HOST = 18, //"invalid host")                                   \
47     HPE_INVALID_PORT = 19, //"invalid port")                                   \
48     HPE_INVALID_PATH = 20, //"invalid path")                                   \
49     HPE_INVALID_QUERY_STRING = 21, //"invalid query string")                   \
50     HPE_INVALID_FRAGMENT = 22, // "invalid fragment")                           \
51     HPE_LF_EXPECTED = 23, //"LF character expected")                           \
52     HPE_INVALID_HEADER_TOKEN = 24, //"invalid character in header")            \
53     HPE_INVALID_CONTENT_LENGTH = 25, //  "invalid character in content-length header")                   \
54     HPE_UNEXPECTED_CONTENT_LENGTH = 26, // "unexpected content-length header")                             \
55     HPE_INVALID_CHUNK_SIZE = 27, // "invalid character in chunk size header")                       \
56     HPE_INVALID_CONSTANT = 28, // "invalid constant string")                    \
57     HPE_INVALID_INTERNAL_STATE = 29, //"encountered unexpected internal state")\
58     HPE_STRICT = 30, // "strict mode assertion failed")                         \
59     HPE_PAUSED = 31, //"parser is paused")                                     \
60     HPE_UNKNOWN = 32 //"an unknown error occurred")
61 }
62 
63 package (collie.codec.http) :
64 
65 enum CR = '\r';
66 enum LF = '\n';
67 
68 enum ubyte[] PROXY_CONNECTION = cast(ubyte[]) "proxy-connection";
69 enum ubyte[] CONNECTION = cast(ubyte[]) "connection";
70 enum ubyte[] CONTENT_LENGTH = cast(ubyte[]) "content-length";
71 enum ubyte[] TRANSFER_ENCODING = cast(ubyte[]) "transfer-encoding";
72 enum ubyte[] UPGRADE = cast(ubyte[]) "upgrade";
73 enum ubyte[] CHUNKED = cast(ubyte[]) "chunked";
74 enum ubyte[] KEEP_ALIVE = cast(ubyte[]) "keep-alive";
75 enum ubyte[] CLOSE = cast(ubyte[]) "close";
76 
77 enum ULLONG_MAX = ulong.max;
78 
79 enum string[33] error_string = [
80     "success" //ok
81     /* Callback-related errors */
82     , "the on_message_begin callback failed" //CB_message_begin
83     ,
84     "the on_url callback failed" //CB_url
85     , "the on_header_field callback failed" //CB_header_field
86     ,
87     "the on_header_value callback failed" //CB_header_value
88     , "the on_headers_complete callback failed" //CB_headers_complete
89     , "the on_body callback failed" //CB_body
90     ,
91     "the on_message_complete callback failed" //CB_message_complete
92     , "the on_status callback failed" //CB_status
93     , "the on_chunk_header callback failed" //CB_chunk_header
94     ,
95     "the on_chunk_complete callback failed" //CB_chunk_complete
96     /* Parsing-related errors */
97     , "stream ended at an unexpected time" //INVALID_EOF_STATE
98     ,
99     "too many header bytes seen; overflow detected" //HEADER_OVERFLOW
100     , "data received after completed connection: close message" //CLOSED_CONNECTION
101     ,
102     "invalid HTTP version" //INVALID_VERSION
103     , "invalid HTTP status code" //INVALID_STATUS
104     , "invalid HTTP method" //INVALID_METHOD
105     , "invalid URL" //INVALID_URL
106     ,
107     "invalid host" //INVALID_HOST
108     , "invalid port" // INVALID_PORT
109     , "invalid query string" //INVALID_QUERY_STRING
110     , "invalid fragment" //INVALID_FRAGMENT
111     ,
112     "LF character expected" //LF_EXPECTED
113     , "invalid character in header" //INVALID_HEADER_TOKEN
114     ,
115     "invalid character in content-length header" //INVALID_CONTENT_LENGTH
116     , "unexpected content-length header" // UNEXPECTED_CONTENT_LENGTH
117     ,
118     "invalid character in chunk size header" //INVALID_CHUNK_SIZE
119     , "invalid constant string" //INVALID_CONSTANT
120     , "encountered unexpected internal state" //INVALID_INTERNAL_STATE
121     ,
122     "strict mode assertion failed" // STRICT
123     , "parser is paused" //PAUSED
124     , "an unknown error occurred" //UNKNOWN
125 ];
126 
127 enum HTTPParserFlags
128 {
129     F_CHUNKED = 1 << 0,
130     F_CONNECTION_KEEP_ALIVE = 1 << 1,
131     F_CONNECTION_CLOSE = 1 << 2,
132     F_CONNECTION_UPGRADE = 1 << 3,
133     F_TRAILING = 1 << 4,
134     F_UPGRADE = 1 << 5,
135     F_SKIPBODY = 1 << 6,
136     F_CONTENTLENGTH = 1 << 7,
137     F_ZERO = 0
138 }
139 
140 enum HTTPParserURLFields
141 {
142     UF_SCHEMA = 0,
143     UF_HOST = 1,
144     UF_PORT = 2,
145     UF_PATH = 3,
146     UF_QUERY = 4,
147     UF_FRAGMENT = 5,
148     UF_USERlogInfo = 6,
149     UF_MAX = 7
150 }
151 
152 __gshared static const char[256] tokens = [ /*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
153 0, 0, 0, 0, 0, 0, 0, 0, /*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
154     0, 0, 0, 0, 0, 0, 0, 0, /*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
155     0, 0, 0, 0, 0, 0, 0, 0, /*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
156     0, 0, 0, 0, 0, 0, 0, 0, /*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
157     0, '!', 0, '#', '$', '%', '&', '\'', /*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
158     0, 0, '*', '+', 0, '-', '.', 0, /*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
159     '0',
160     '1', '2', '3', '4', '5', '6', '7', /*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
161     '8', '9', 0, 0, 0, 0, 0, 0, /*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
162     0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
163     'h', 'i',
164     'j', 'k', 'l', 'm', 'n', 'o', /*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
165     'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
166     'x',
167     'y', 'z', 0, 0, 0, '^', '_', /*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
168     '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
169     'h',
170     'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
171     'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
172     /* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
173     'x', 'y', 'z', 0, '|', 0, '~', 0];
174 
175 __gshared static const byte[256] unhex = [-1, -1, -1, -1, -1, -1, -1,
176     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
177     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
178     -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1,
179     -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
180     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
181     -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
182     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
183 
184 version (HTTP_PARSER_STRICT)
185 {
186     pragma(inline,true)
187     ubyte T(ubyte v)
188     {
189         return 0;
190     }
191 }
192 else
193 {
194     pragma(inline,true)
195     ubyte T(ubyte v)
196     {
197         return v;
198     }
199 }
200 
201 __gshared const ubyte[32] normal_url_char = [ /*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
202 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
203     0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, /*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
204     0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
205     0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
206     0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, /*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
207     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
208     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
209     1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, /*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
210     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
211     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
212     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
213     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
214     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
215     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
216     1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
217     1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,];
218 
219 enum HTTPParserState
220 {
221     s_dead = 1 /* important that this is > 0 */
222 
223     ,
224     s_start_req_or_res,
225     s_res_or_resp_H,
226     s_start_res,
227     s_res_H,
228     s_res_HT,
229     s_res_HTT,
230     s_res_HTTP,
231     s_res_first_http_major,
232     s_res_http_major,
233     s_res_first_http_minor,
234     s_res_http_minor,
235     s_res_first_status_code,
236     s_res_status_code,
237     s_res_status_start,
238     s_res_status,
239     s_res_line_almost_done,
240     s_start_req,
241     s_req_method,
242     s_req_spaces_before_url,
243     s_req_schema,
244     s_req_schema_slash,
245     s_req_schema_slash_slash,
246     s_req_server_start,
247     s_req_server,
248     s_req_server_with_at,
249     s_req_path,
250     s_req_query_string_start,
251     s_req_query_string,
252     s_req_fragment_start,
253     s_req_fragment,
254     s_req_http_start,
255     s_req_http_H,
256     s_req_http_HT,
257     s_req_http_HTT,
258     s_req_http_HTTP,
259     s_req_first_http_major,
260     s_req_http_major,
261     s_req_first_http_minor,
262     s_req_http_minor,
263     s_req_line_almost_done,
264     s_header_field_start,
265     s_header_field,
266     s_header_value_discard_ws,
267     s_header_value_discard_ws_almost_done,
268     s_header_value_discard_lws,
269     s_header_value_start,
270     s_header_value,
271     s_header_value_lws,
272     s_header_almost_done,
273     s_chunk_size_start,
274     s_chunk_size,
275     s_chunk_parameters,
276     s_chunk_size_almost_done,
277     s_headers_almost_done,
278     s_headers_done /* Important: 's_headers_done' must be the last 'header' state. All
279    * states beyond this must be 'body' states. It is used for overflow
280    * checking. See the PARSING_HEADER() macro.
281    */
282 
283     ,
284     s_chunk_data,
285     s_chunk_data_almost_done,
286     s_chunk_data_done,
287     s_body_identity,
288     s_body_identity_eof,
289     s_message_done
290 }
291 
292 enum HTTPParserHeaderstates
293 {
294     h_general = 0,
295     h_C,
296     h_CO,
297     h_CON,
298     h_matching_connection,
299     h_matching_proxy_connection,
300     h_matching_content_length,
301     h_matching_transfer_encoding,
302     h_matching_upgrade,
303     h_connection,
304     h_content_length,
305     h_transfer_encoding,
306     h_upgrade,
307     h_matching_transfer_encoding_chunked,
308     h_matching_connection_token_start,
309     h_matching_connection_keep_alive,
310     h_matching_connection_close,
311     h_matching_connection_upgrade,
312     h_matching_connection_token,
313     h_transfer_encoding_chunked,
314     h_connection_keep_alive,
315     h_connection_close,
316     h_connection_upgrade
317 }
318 
319 enum HTTPParserHostState
320 {
321     s_http_host_dead = 1,
322     s_http_userlogInfo_start,
323     s_http_userlogInfo,
324     s_http_host_start,
325     s_http_host_v6_start,
326     s_http_host,
327     s_http_host_v6,
328     s_http_host_v6_end,
329     s_http_host_v6_zone_start,
330     s_http_host_v6_zone,
331     s_http_host_port_start,
332     s_http_host_port
333 }